package com.example.a15;

import org.aopalliance.intercept.MethodInterceptor;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;

public class A15Application {

    @Aspect
    static class MyAspect {

        @Before("execution(* foo())")
        public void before() {
            System.out.println("前置通知");
        }

        @After("execution(* foo())")
        public void after() {
            System.out.println("后置增强");
        }
    }

    public static void main(String[] args) {
        /*
            两个切面概念
            aspect =
                    通知1(advice) + 切点1(pointcut)
                    通知2(advice) + 切点2(pointcut)
                    通知3(advice) + 切点3(pointcut)
                    ...
            advisor = 更细粒度的切面，包含一个通知和切点
         */

        // 1. 备好切点
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* foo())");
        // 2. 备好通知
        MethodInterceptor advice = invocation -> {
            System.out.println("before...");
            Object result = invocation.proceed(); // 调用目标
            System.out.println("after...");
            return result;
        };
        // 3. 备好切面
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);

        /*
            4. 创建代理
                a. proxyTargetClass = false， 目标实现了接口，用 jdk 实现
                b. proxyTargetClass = false， 目标没有实现接口，用 cglib 实现
                c. proxyTargetClass = true， 总是使用 cglib 实现
         */
        Target2 target = new Target2();
        ProxyFactory factory = new ProxyFactory();
        factory.setTarget(target); // 设置目标对象
        factory.addAdvisor(advisor); // 设置切面
        factory.setInterfaces(target.getClass().getInterfaces()); // 代理实现哪些接口
        factory.setProxyTargetClass(false); // 是否直接代理目标类
//        I1 proxy = (I1) factory.getProxy();
        Target2 proxy = (Target2) factory.getProxy();
        System.out.println(proxy.getClass());
        proxy.foo();
        proxy.bar();

        /*
            小结:
                a. Spring 的代理选择规则
                b. 底层的切点实现
                c. 底层的通知实现
                d. ProxyFactory 是用来创建代理的核心实现，用 AopProxyFactory 选择具体代理实现
                    - JdkDynamicAopFactory
                    - ObjenesisCglibAopProxy
         */

    }

    interface I1 {

        void foo();

        void bar();

    }

    static class Target1 implements I1 {

        @Override
        public void foo() {
            System.out.println("target1 foo()");
        }

        @Override
        public void bar() {
            System.out.println("target1 bar()");
        }
    }

    static class Target2 {
        public void foo() {
            System.out.println("target2 foo");
        }

        public void bar() {
            System.out.println("target2 bar");
        }
    }

}
